###############################################################################
# SuperLinks                                                                  #
# Copyright (c) 2000-2007 Greg Nolle (http://greg.nolle.co.uk)                #
###############################################################################
# This program is free software; you can redistribute it and/or modify it     #
# under the terms of the GNU General Public License as published by the Free  #
# Software Foundation; either version 2 of the License, or (at your option)   #
# any later version.                                                          #
#                                                                             #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       #
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for   #
# more details.                                                               ##                                                                             #
# You should have received a copy of the GNU General Public License along     #
# with this program; if not, write to the Free Software Foundation, Inc.,     #
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.                 #
###############################################################################
# Libraries/Authenticate.pm.pl -> Authenticate library                        #
###############################################################################
# DON'T EDIT BELOW UNLESS YOU KNOW WHAT YOU'RE DOING!                         #
###############################################################################
package Authenticate;

BEGIN { require "System.pm.pl"; import System qw($SYSTEM); }
BEGIN { require "General.pm.pl"; import General qw($GENERAL); }
require "Error.pm.pl";

use strict;

###############################################################################
# CP function
sub CP {
  my %in = ("DB" => undef, "ACTION" => "", "CATEGORIES" => [], @_);

  my ($Account, $Session);

  {
    if ($SL::QUERY{'Username'} && $SL::QUERY{'Password'}) {
      ($Account, $Session) = &myManual(DB => $in{'DB'});
      last;
    }
    
    if ($SL::QUERY{'SID'}) {
      ( ($Account, $Session) = &mySID(DB => $in{'DB'}) ) and last;
    }
    
    if ($SL::COOKIES{'CP-SID'}) {
      ( ($Account, $Session) = &myCookieSID(DB => $in{'DB'}) ) and last;
    }
    
    if ($SL::COOKIES{'CP-Username'} && $SL::COOKIES{'CP-Password'}) {
      ( ($Account, $Session) = &myCookieManual(DB => $in{'DB'}) ) and last;
    }
  
    require "ControlPanel/Login.pm.pl";
    my $Source = CP::Login->new();
       $Source->show(DB => $in{'DB'});
    exit;
  }
  
  %SL::ADMIN = (%SL::ADMIN, %{ $Account }, SID => $Session->{'ID'});

  unless ($Account->{'STATUS'}) {
    &Error::Error("CP", MESSAGE => "Your account is inactive");
  }

  my $Level = $in{'DB'}->BinarySelect(
    TABLE   => "Levels",
    KEY     => $Account->{'LEVEL'}
  );
  
  $SL::ADMIN{'level'} = $Level;

  return 1 unless ($in{'ACTION'});
  
  &CheckPermission(ACTION => $in{'ACTION'}, CATEGORIES => $in{'CATEGORIES'});
  
  return 1;
}

###############################################################################
# CheckPermission function
sub CheckPermission {
  my %in = ("ACTION" => "", "CATEGORIES" => [], "RETURN" => 0, @_);

  return 1 unless ($in{'ACTION'});
  
  my $Perms = eval($SL::ADMIN{'level'}->{'PERMISSIONS'});
  
  return 1 if ($Perms->{'SUPERUSER'});
  
  if (scalar(@{ $in{'CATEGORIES'} }) >= 1) {
    my $error;
    foreach my $category (@{ $in{'CATEGORIES'} }) {
      next if ($Perms->{'CATEGORIES'}->{$category}->{$in{'ACTION'}});
      next if (!defined($Perms->{'CATEGORIES'}->{$category}->{$in{'ACTION'}}) && $Perms->{$in{'ACTION'}});
      $error = 1;
    }
    return 1 unless ($error);
  } else {
    return 1 if ($Perms->{$in{'ACTION'}});
  }
  
  return if ($in{'RETURN'});
  &Error::Error("CP", MESSAGE => "You have insufficient permissions to access this feature");
}

###############################################################################
# FilterCategories function
sub FilterCategories {
  my %in = ("CATEGORIES" => [], "ACTION" => "", @_);
  
  return $in{'CATEGORIES'} unless ($in{'ACTION'});
  
  my (@Return, %Index);
  
  foreach my $category (@{ $in{'CATEGORIES'} }) {
    next unless (&CheckPermission(ACTION => $in{'ACTION'}, CATEGORIES => [$category->{'ID'}], RETURN => 1));
    push(@Return, $category);
    $Index{ $category->{'ID'} } = $#Return;
  }
  
  return (wantarray ? (\@Return, \%Index) : \@Return);
}

###############################################################################
# myManual function
sub myManual {
  my %in = ("DB" => undef, @_);
  
  return unless ($SL::QUERY{'Username'} && $SL::QUERY{'Password'});
  
  my $Account = $in{'DB'}->BinarySelect(
    TABLE   => "Admins",
    KEY     => $SL::QUERY{'Username'}
  );
  unless ($Account) {
    require "ControlPanel/Login.pm.pl";
    my $Source = CP::Login->new();
       $Source->show(DB => $in{'DB'}, ERROR => "INVALID-Username");
    exit;
  }
  unless ($SL::QUERY{'Password'} eq $Account->{'PASSWORD'}) {
    require "ControlPanel/Login.pm.pl";
    my $Source = CP::Login->new();
       $Source->show(DB => $in{'DB'}, ERROR => "INVALID-Password");
    exit;
  }
    
  my $Session = {
    USERNAME      => $SL::QUERY{'Username'},
    PASSWORD      => $SL::QUERY{'Password'},
    IP            => $ENV{'REMOTE_ADDR'},
    LOGIN_SECOND  => time
  };
    
  (
    $Session->{'ID'} = $in{'DB'}->Insert(
      TABLE   => "Sessions",
      VALUES  => $Session
    )
  ) || &Error::Error("CP", MESSAGE => "Error inserting record. $in{'DB'}->{'ERROR'}");
    
  $SL::COOKIES{'CP-SID'} = $Session->{'ID'};

  return ($Account, $Session);
}

###############################################################################
# mySID function
sub mySID {
  my %in = ("DB" => undef, @_);
  
  return unless ($SL::QUERY{'SID'});

  my $Session = $in{'DB'}->BinarySelect(
    TABLE   => "Sessions",
    KEY     => $SL::QUERY{'SID'}
  );

  return unless ($Session);    
  return unless ($Session->{'IP'} eq $ENV{'REMOTE_ADDR'});
    
  if ($Session->{'LOGIN_SECOND'} < (time - 30 * 24 * 60 * 60)) {
    (
      $in{'DB'}->Delete(
        TABLE   => "Sessions",
        KEYS    => [$SL::QUERY{'SID'}]
      )
    ) || &Error::Error("CP", MESSAGE => "Error deleting record. $in{'DB'}->{'ERROR'}");
    return;
  }
    
  my $Account = $in{'DB'}->BinarySelect(
    TABLE => "Admins",
    KEY   => $Session->{'USERNAME'}
  );
    
  return unless ($Account);
  return unless ($Account->{'PASSWORD'} eq $Session->{'PASSWORD'});
    
  (
    $in{'DB'}->Update(
      TABLE   => "Sessions",
      VALUES  => {
        LOGIN_SECOND  => time
      },
      KEY     => $SL::QUERY{'SID'}
    )
  ) || &Error::Error("CP", MESSAGE => "Error updating record.1 $in{'DB'}->{'ERROR'}");
    
  $SL::COOKIES{'CP-SID'} = $SL::QUERY{'SID'};

  return ($Account, $Session);
}

###############################################################################
# myCookieSID function
sub myCookieSID {
  my %in = ("DB" => undef, @_);
  
  return unless ($SL::COOKIES{'CP-SID'});

  my $Session = $in{'DB'}->BinarySelect(
    TABLE   => "Sessions",
    KEY     => $SL::COOKIES{'CP-SID'}
  );
  if (!$Session || $Session->{'IP'} ne $ENV{'REMOTE_ADDR'}) {
    $SL::COOKIES{'CP-SID'} = "";
    return;
  }
    
  if ($Session->{'LOGIN_SECOND'} < (time - 30 * 24 * 60 * 60)) {
    (
      $in{'DB'}->Delete(
        TABLE   => "Sessions",
        KEYS    => [$SL::COOKIES{'CP-SID'}]
      )
    ) || &Error::Error("CP", MESSAGE => "Error deleting record. $in{'DB'}->{'ERROR'}");
    $SL::COOKIES{'CP-SID'} = "";
    return;
  }
    
  my $Account = $in{'DB'}->BinarySelect(
    TABLE => "Admins",
    KEY   => $Session->{'USERNAME'}
  );

  if (!$Account || $Account->{'PASSWORD'} ne $Session->{'PASSWORD'}) {    
    $SL::COOKIES{'CP-SID'} = "";
    return;
  }
    
  (
    $in{'DB'}->Update(
      TABLE   => "Sessions",
      VALUES  => {
        LOGIN_SECOND  => time
      },
      KEY     => $SL::COOKIES{'CP-SID'}
    )
  ) || &Error::Error("CP", MESSAGE => "Error updating record. $in{'DB'}->{'ERROR'}");
    
  return ($Account, $Session);
}

###############################################################################
# myCookieManual function
sub myCookieManual {
  my %in = ("DB" => undef, @_);
  
  return unless ($SL::COOKIES{'CP-Username'} && $SL::COOKIES{'CP-Password'});

  my $Account = $in{'DB'}->BinarySelect(
    TABLE => "Admins",
    KEY   => $SL::COOKIES{'CP-Username'}
  );
  unless ($Account && $Account->{'PASSWORD'} eq $SL::COOKIES{'CP-Password'}) {
    $SL::COOKIES{'CP-Username'} = "";
    $SL::COOKIES{'CP-Password'} = "";
    return;
  }
  
  my $Session = {
    USERNAME      => $SL::COOKIES{'CP-Username'},
    PASSWORD      => $SL::COOKIES{'CP-Password'},
    IP            => $ENV{'REMOTE_ADDR'},
    LOGIN_SECOND  => time
  };
    
  (
    $Session->{'ID'} = $in{'DB'}->Insert(
      TABLE   => "Sessions",
      VALUES  => $Session
    )
  ) || &Error::Error("CP", MESSAGE => "Error inserting record. $in{'DB'}->{'ERROR'}");
    
  $SL::COOKIES{'CP-SID'} = $Session->{'ID'};

  return ($Account, $Session);
}

1;